package edu.pku.sei.transformation.structure;

import java.util.ArrayList;
import java.util.List;

import edu.pku.sei.mdabase.core.IDataType;
import edu.pku.sei.mdabase.core.INamedElement;
import edu.pku.sei.mdabase.infrastructure.runtime.Variable;
import edu.pku.sei.transformation.pattern.TPatternEdge;
import edu.pku.sei.transformation.pattern.TPatternNode;

public class Rule implements INamedElement{
	private List<PatternDomain> domains = new ArrayList<PatternDomain>();
	
	private Clause preClause = new Clause();
	private Clause postClause = new Clause();

	private Clause initClause = new Clause();
	private Clause bodyClause = new Clause();
	
	private List<Variable> variableDeclaration = new ArrayList<Variable>();
	
	private boolean isTop;
	
	public boolean isTop()
	{
		return isTop;
	}

	public void setTop(boolean isTop)
	{
		this.isTop = isTop;
	}

	public Rule(){
		preClause.setOwner(this);
		postClause.setOwner(this);
		initClause.setOwner(this);
		bodyClause.setOwner(this);
	}
	
	public Object getVariable(String name){
		if(variableDeclaration!=null){
			for(Variable v : variableDeclaration){
				if(v.getName().equals(name))
					return v;
			}
		}
		
		for(PatternDomain d: domains){
			for(TPatternNode n : d.getPattern().getNodes()) {
				if(n.getName().equals(name))
					return n;
			}
		}
		return null;
	}
	
	private int priority = 0;

	public int getPriority() {
		return priority;
	}

	public void setPriority(int priority) {
		this.priority = priority;
	}

	public Clause getPreClause() {
		return preClause;
	}

	public Clause getPostClause() {
		return postClause;
	}

	public Clause getInitClause() {
		return initClause;
	}
	
	public Clause getBodyClause() {
		return bodyClause;
	}
	
	public List<Variable> getVariableDeclaration()
	{
		return variableDeclaration;
	}

	public List<PatternDomain> getDomains(){
		return domains;
	}
	
	public void addPatternDomain(PatternDomain domain){
		domains.add(domain);
		domain.setOwner(this);
	}
	
	public List<Domain> getDomains(TypedModel para) {
		List<Domain> result = new ArrayList<Domain>();
		for(PatternDomain d : domains){
			if(d.getFormalParameter()==para){
				result.add(d);
			}
		}
		return result;
	}
	

	private String name;
	
	@Override
	public String getName() {
		return name;
	}

	@Override
	public void setName(String name) {
		this.name=name;
	}
	
	private Transformation owner;

	public Transformation getOwner() {
		return owner;
	}

	public void setOwner(Transformation owner) {
		this.owner = owner;
	}
	
	public void declareVariable(String name ,IDataType type, String domainName)
	{
		declareVariable(name, type, Variable.UNINITIATED_VALUE, domainName);
	}
	
	public void declareVariable(String name, IDataType type,Object defaultValue, String domainName)
	{
		Variable v = new Variable();
		v.setName(name);
		v.setType(type);
		v.setValue(defaultValue);
		v.setDomainName(domainName);
		variableDeclaration.add(v);
	}

	
	public PatternDomain getContainedDomain(TPatternNode tn)
	{
		for (PatternDomain domain : domains)
		{
			if (domain.getPattern().containsNode(tn.getName()))
				return domain;
		}
		return null;
	}

	public IDataType getVarType(String name)
	{
		for (Variable var : variableDeclaration)
		{
			if (var.getName().equals(name))
				return var.getType();
		}
		for (PatternDomain domain : domains)
		{
			for (TPatternNode node : domain.getPattern().getNodes())
			{
				if (node.getName().equals(name))
					return node.getType();
			}
			for (TPatternEdge edge : domain.getPattern().getEdges())
			{
				if (edge.getName().equals(name))
					return edge.getType();
			}
		}
		return null;
	}
}
